package com.daichi.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.daichi.common.lang.Const;
import com.daichi.entity.SysMenu;
import com.daichi.entity.SysRole;
import com.daichi.entity.SysUser;
import com.daichi.mapper.SysUserMapper;
import com.daichi.service.SysMenuService;
import com.daichi.service.SysRoleService;
import com.daichi.service.SysUserService;
import com.daichi.utils.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author Daichi Chou
 * @since 2021-06-05
 */
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {

    private final SysRoleService sysRoleService;

    private final SysUserMapper sysUserMapper;

    private final SysMenuService sysMenuService;

    private final RedisUtil redisUtil;

    @Autowired
    public SysUserServiceImpl(SysMenuService sysMenuService, SysRoleService sysRoleService, SysUserMapper sysUserMapper, RedisUtil redisUtil) {
        this.sysMenuService = sysMenuService;
        this.sysRoleService = sysRoleService;
        this.sysUserMapper = sysUserMapper;
        this.redisUtil = redisUtil;
    }

    @Override
    public SysUser getUserByName(String username) {
        if (redisUtil.hasKey(Const.REDIS_USER_PREFIX + username)) {
            return JSON.parseObject(redisUtil.getString(Const.REDIS_USER_PREFIX + username), SysUser.class);
        }
        return cacheUserByName(username);
    }

    @Override
    public SysUser cacheUserByName(String username) {
        SysUser sysUser = this.getOne(new QueryWrapper<SysUser>().eq("username", username));
        if (sysUser == null) {
            return null;
        }
        redisUtil.set(Const.REDIS_USER_PREFIX + username, sysUser, 60 * 60);
        return sysUser;
    }

    @Override
    public String getUserAuthorityInfo(String username) {

        SysUser sysUser = this.getUserByName(username);

        if (sysUser == null) {
            return null;
        }

        if (redisUtil.hasKey(Const.REDIS_AUTHORITY_PREFIX + username)) {
            return (String) redisUtil.get(Const.REDIS_AUTHORITY_PREFIX + username);
        }

        StringBuilder authority = new StringBuilder();

        List<SysRole> roleList = sysRoleService.list(new QueryWrapper<SysRole>().inSql("id", "select role_id from sys_user_role where user_id=" + sysUser.getId()));

        if (CollectionUtil.isNotEmpty(roleList)) {
            authority.append(roleList.stream().map(role -> "ROLE_" + role.getCode()).collect(Collectors.joining(",")));
        }

        List<Long> menuIds = sysUserMapper.getNavMenuIds(sysUser.getId());

        if (CollectionUtil.isNotEmpty(menuIds)) {
            List<SysMenu> menuList = sysMenuService.listByIds(menuIds);
            if (CollectionUtil.isNotEmpty(menuList)) {
                String perms = menuList.stream().map(SysMenu::getPerms).collect(Collectors.joining(","));
                if (StrUtil.isNotEmpty(authority)) {
                    authority.append(",");
                }
                authority.append(perms);
            }
        }

        redisUtil.set(Const.REDIS_AUTHORITY_PREFIX + username, authority.toString(), 60 * 60);

        return authority.toString();
    }


    @Override
    public void clearUserAuthorityInfo(String username) {
        redisUtil.del(Const.REDIS_AUTHORITY_PREFIX + username);
    }

    @Override
    public void clearUserAuthorityInfoByRoleId(Long roleId) {
        List<SysUser> sysUsers = this.list(new QueryWrapper<SysUser>()
                .inSql("id", "select user_id from sys_user_role where role_id = " + roleId));

        sysUsers.forEach(user -> {
            this.clearUserAuthorityInfo(user.getUsername());
        });
    }

    @Override
    public void clearUserAuthorityInfoByMenuId(Long menuId) {
        List<SysUser> sysUsers = sysUserMapper.listByMenuId(menuId);

        sysUsers.forEach(user -> {
            this.clearUserAuthorityInfo(user.getUsername());
        });
    }

    @Override
    public void clearUserInfo(String username) {
        redisUtil.del(Const.REDIS_USER_PREFIX + username);
    }

}
